package exchange

import (
	"global/core"
	"srv/cmc/cap"
	"github.com/parnurzeal/gorequest"
	"time"
	"global/constants"
	"global/libs/structs"
	"encoding/json"
	"github.com/ngaut/log"
	"strings"
	"strconv"
	"os"
	"global/model"
	"global/util"
)

type ExchangeMetaData struct {
	Ctx 		*core.Context
	Client 		*gorequest.SuperAgent
	Key 		string
	IntervalC 	*time.Ticker
}

func NewExchangeMetaData() cap.InterfaceCmc {
	return &ExchangeMetaData{
		IntervalC: 		time.NewTicker(1 * time.Hour),
	}
}

func (e *ExchangeMetaData) Init(ctx *core.Context) cap.InterfaceCmc {
	e.Ctx = ctx
	e.Client = gorequest.New()
	e.Key = e.Ctx.AccountConfig()
	return e
}

func (e *ExchangeMetaData) Run() error {
	e.handler()
	return nil
}

func (e *ExchangeMetaData) handler()  {
	exchangeMaps, err := e.getCmcIdMap()
	if err != nil {
		util.ErrorAndExit("Error: %s", err.Error())
	}

	exchangeIds := make([]string, 0)
	for _, exchange := range exchangeMaps {
		exchangeIds = append(exchangeIds, strconv.Itoa(exchange.Id))
	}

	exchangeInfos, err := e.getCmcExchangeMetaData(exchangeIds)
	if err != nil {
		util.ErrorAndExit("Error: %s", err.Error())
	}


	var datas []*model.Exchange
	for _, item := range exchangeInfos {
		var webSite, twitter, blog, chat, fee string
		if len(item.Urls.WebSite) > 0 {
			webSite = item.Urls.WebSite[0]
		}

		if len(item.Urls.Twitter) > 0 {
			twitter = item.Urls.Twitter[0]
		}

		if len(item.Urls.Blog) > 0 {
			blog = item.Urls.Blog[0]
		}

		if len(item.Urls.Chat) > 0 {
			chat = item.Urls.Chat[0]
		}

		if len(item.Urls.Fee) > 0 {
			fee = item.Urls.Fee[0]
		}

		// download url
		logoUrl, err := util.DownloadImg(item.Logo, item.Slug, "exchanges")
		if err != nil {
			log.Errorf("Error: %s", err)
			logoUrl = ""
		}

		datas = append(datas, &model.Exchange{
			Mid: 			item.Id,
			NameEn: 		item.Name,
			NameCn: 		"",
			Slug: 			item.Slug,
			Logo: 			logoUrl,
			Mode: 			"",
			Description: 	"",
			Country: 		"",
			Website: 		webSite,
			Twitter: 		twitter,
			Blog: 			blog,
			Chat: 			chat,
			Fee: 			fee,
			Enable: 		model.ExchangeDisabled,
			Sort: 			0,
			Recommend: 		0,
			RecommendSort:  0,
			CreateTime: 	time.Now(),
			UpdateTime: 	time.Now(),
		})
	}

	if err = model.ExchangeModel.InsertMulti(datas); err != nil {
		log.Errorf("Insert multi failed, try insert items one by one. msg: %s", err)
		// 逐条插入
		for _, v := range datas {
			if ok, err := model.ExchangeModel.Insert(v); !ok {
				log.Errorf("Error: %s", err)
			}
		}
	}

	log.Infof("get exchange metadata complete, count: %d", len(datas))
	os.Exit(1)
}

// 获取交易所元数据
func (e *ExchangeMetaData) getCmcExchangeMetaData(ids []string) (map[string]structs.CmcExchangeMetaData, error) {
	_, body, errs := e.Client.
		Get(core.GetCmcUrl(e.Ctx.IsDebug(), constants.CmcExchangeInfoUrl)).
		Set("X-CMC_PRO_API_KEY", e.Key).
		Query(map[string]interface{}{
			"id": strings.Join(ids, ","),
		}).
		End()

	if len(errs) != 0 {
		return nil, errs[0]
	}

	type bodyData struct {
		Status 			structs.CmcStatus		`json:"status"`
		Data 			map[string]structs.CmcExchangeMetaData 	`json:"data"`
	}

	var parsedData bodyData
	err := json.Unmarshal([]byte(body), &parsedData)
	if err != nil {
		return nil, err
	}

	return parsedData.Data, nil
}

func (e *ExchangeMetaData) getCmcIdMap() ([]structs.CmcExchangeIdMap, error) {
	_, body, errs := e.Client.
		Get(core.GetCmcUrl(e.Ctx.IsDebug(), constants.CmcExchangeMapUrl)).
		Set("X-CMC_PRO_API_KEY", e.Key).
		End()

		if len(errs) != 0 {
			return nil, errs[0]
		}

	type bodyData struct {
		Status 		structs.CmcStatus			`json:"status"`
		Data 		[]structs.CmcExchangeIdMap 	`json:"data"`
	}

	var parsedBody bodyData
	err := json.Unmarshal([]byte(body), &parsedBody)
	if err != nil {
		return nil, err
	}

	return parsedBody.Data, nil
}